Analyse des variations du bitcoin en fonction d’indicateurs techniques
Table des matières
Figure 1 : Image générée par Midjourney
Contexte et objectifs du projet
Le bitcoin est une monnaie virtuelle décentralisée qui opère indépendamment des banques et des gouvernements. Cela signifie que ces monnaies ne sont pas émises par une autorité centrale (un État par exemple) mais via des algorithmes exécutés sur un réseau informatique assurant leur cohérence et la sécurité des transactions.
Bien que le potentiel économique du bitcoin reste à évaluer, ce dernier offre déjà à certains pays en développement une alternative de financement pertinente comparée aux monnaies traditionnelles gérées par des infrastructures bancaires ou des institutions étatiques. Toutefois, le bitcoin est une monnaie qui s’avère parfois très volatile. Expliquer ses fluctuations apparaît donc comme un enjeu socio-économique fort pour les prochaines années.
Travaux à réaliser
Dans le domaine de l'analyse des marchés financiers, l'analyse technique correspond à un ensemble d'outils dont le but est de prédire les rendements futurs des actifs financiers (actions, obligations, matières premières, cryptomonnaies, etc). Les analyses reposent sur l'étude des historiques des données de marché disponibles, principalement la cotation et le volume des actifs considérés.
Ce projet a pour objectif d’étudier l’influence d'indicateurs techniques financiers sur la valorisation du bitcoin (BTC).
Le travail attendu dans ce projet est le suivant :
- Montée en compétences sur le vocabulaire du domaine de l'analyse financière
- Analyse descriptive univariée des variations de la cotation du BTC (e.g. distribution des rendements, volatilité hebdomadaire, mensuelle, annuelle, intra-journalière, etc.).
- Analyse descriptive multivariée des variations du BTC en fonction des indicateurs techniques considérés.
- Développement d’un ou plusieurs modèles explicatifs pour les variations du BTC.
- Évaluation des performances prédictives des modèles mis en œuvre.
Du point de vue technique, les développements sont à réaliser avec le langage Python.
Présentation des données
L'évolution de la cotation d'un actif au cours du temps est usuellement présentée sous la forme de données, dites au format OHLCV (de l'anglais open, high, low, close, volume). Il s'agit d'un format pratique permettant de représenter des séries temporelles d'une manière particulière. En effet, le format OHLC (la partie volume n'est pas concernée par la subtilité du format) représente l'évolution d'une mesure au cours d'intervalles de temps réguliers successifs caractérisés par une période d'échantillonnage notée \(\Delta t\) (e.g. une minute, cinq minutes, une heure, une journée, etc).
Typiquement, les données OHLCV contiennent les variables suivantes :
timestamp: timestamp caractérisant le début de la période de mesure (par exemple exprimé en millisecondes), la fin étant déterminée par la période d'échantillonnage \(\Delta t\) utilisée.open: valeur de l'actif au début de la période.high: valeur maximum de l'actif atteinte sur la période.low: valeur mimimum de l'actif atteinte sur la période.close: valeur de l'actif à la fin de la période.volume: montant cumulé des ventes et des achats de l'actif sur la période.
Il est courant de visualiser les données OHLC à l'aide du graphique, dit en chandeliers. En fonction, des valeurs d'ouverture (open) et de fermeture (close), on parle également de chandeliers haussiers et baissiers, cf. Figure 2.
Figure 2 : Représentation du symbole de chandelier.
Dans un diagramme en chandelier, on retrouve les données OHLC mais également les notions de :
- corps (body) représentant la distance entre la cotation d'ouverture et de fermeture de l'actif sur une période ;
- mèches ou ombres supérieures (upper shadow) représentant la distance entre la partie haute du corps et la cotation la plus haute sur une période ;
- mèches ou ombres inférieures (lower shadow) représentant la distance entre la partie basse du corps et la cotation la plus basse sur une période ;
Dans ce projet nous allons travailler sur les données de cotation du Bitcoin (BTC) par rapport au Dollar (USDT) échantillonnées à une période de 5 minutes sur les années 2021 et 2022.
Le fichier de données est accessible en suivant ce lien de téléchargement Le tableau suivant donne un aperçu des 25 premières minutes de cotations du BTC/USDT de l'année 2021.
import pandas as pd ohlcv_df = pd.read_csv("btc_5m_2021_2022.csv.bz2", compression="bz2", index_col="time") ohlcv_df
| open | high | low | close | volume | |
|---|---|---|---|---|---|
| time | |||||
| 2021-01-01 00:00:00+00:00 | 28 923.63 | 29 017.50 | 28 913.12 | 28 975.65 | 182.89 |
| 2021-01-01 00:05:00+00:00 | 28 975.65 | 28 979.53 | 28 846.28 | 28 858.94 | 214.57 |
| 2021-01-01 00:10:00+00:00 | 28 858.94 | 28 883.20 | 28 690.17 | 28 752.80 | 442.62 |
| 2021-01-01 00:15:00+00:00 | 28 752.80 | 28 852.48 | 28 720.91 | 28 820.72 | 174.84 |
| 2021-01-01 00:20:00+00:00 | 28 822.17 | 28 846.46 | 28 744.09 | 28 846.46 | 161.32 |
Par exemple, la première ligne du tableau signifie que le 01/01/2021 :
- à 00:00:00, le prix d'un BTC était de 28923.63 USDT ;
- à 00:05:00, le prix d'un BTC était de 28975.65 USDT (cotation de fermeture de la période de 00:00:00 et cotation d'ouverture de la période 00:05:00) ;
- entre 00:00:00 et 00:05:00 le prix d'un BTC est passé par un minimum de 28913.12 USDT et un maximum de 29017.5 USDT.
Note : Le marché BTC/USDT étant ouvert 24h/24 et 7j/7, nous devrions observer \(\text{close}(t-1)\) égale à \(\text{open}(t)\) pour tout \(t\). Toutefois, la collecte des données n'étant pas instantanée, il est fréquent d'observer de légères différences entre le cours d'ouverture de la période courante et le cours de fermeture de la période précédente.
Notations mathématiques
Notions temporelles
Nous avons introduit précédemment la période d'échantillonnage des données \(\Delta t\). On note également \(t_{0}\) la première date d'échantillonnage. Dans l'exemple de données précédent, on rappelle que \(\Delta t = 5\) minutes et que \(t_{0} =\) 2021-01-01 00:00:00.
Nous introduisons ensuite l'indice \(p \ge 0\) permettant de référencer la \(p\) -ème période d'observation des données (cf. Figure 3), i.e. entre \(t_{0} + p\Delta t\) et \(t_{0} + (p+1)\Delta t\). En reprenant l'exemple précédent, on a :
- 1er période d'observation \(p = 0\) : période entre 2021-01-01 00:00:00 et 2021-01-01 00:05:00 ;
- 5ème période d'observation \(p = 4\) : période entre 2021-01-01 00:20:00 et 2021-01-01 00:25:00.
Figure 3 : Notion de période sur les données OHLCV.
Les données OHLCV sont notées dans la suite comme suit :
- \(\text{o}_{p}\) : cotation de l'actif à l'ouverture de la période \(p\), i.e. à \(t = t_{0} + p\Delta t\) ;
- \(\text{c}_{p}\) : cotation de l'actif à la fermeture de la période \(p\), i.e. à \(t = t_{0} + (p+1)\Delta t\) ;
- \(\text{h}_{p}\) : cotation maximum de l'actif sur la période \(p\) ;
- \(\text{l}_{p}\) : cotation mimimum de l'actif sur la période \(p\) ;
- \(\text{v}_{p}\) : volume échangé de l'actif la période \(p\).
Rendements
On note enfin \(r_{p}\) la variation relative de la cotation d'un actif entre deux périodes consécutives, on parle également de rendement (ou returns en anglais) sur la période \(p\). Nous avons donc pour tout \(p \ge 1\) :
\begin{equation} \label{org8e76f31} r_{p} = \frac{\text{c}_{p}}{\text{c}_{p - 1}} - 1. \end{equation}La quantité \(r_{p}\) est donc positive si le BTC gagne en valeur par rapport à l'USDT sur la période \(p\) et négative sinon. Le rendement représente l'indicateur principal au coeur de toutes les analyses financières réalisées sur un actif donné.
La définition \eqref{org8e76f31} porte sur un rendement entre deux périodes successives. Cette définition peut être étendue entre deux périodes \(p\) et \(p + k\) données (cf. Figure 4) comme suit :
\begin{equation} \rho_{p + k} = \frac{\text{c}_{p + k}}{\text{c}_{p-1}} - 1, \end{equation}avec \(k \ge 0\) un nombre entier permettant de définir le nombre de périodes futures à prendre en compte pour le calcul du rendement.
Figure 4 : Illustration graphique du calcul d'un rendement de clôture.
Exemples
Nous illustrons les définitions précédentes sur l'extrait de cotation BTC/USDT suivant.
import plotly.graph_objects as go ohlcv_ex_df = ohlcv_df.head(10) fig = go.Figure() fig.add_trace(go.Candlestick(x=ohlcv_ex_df.index, open=ohlcv_ex_df["open"], high=ohlcv_ex_df["high"], low=ohlcv_ex_df["low"], close=ohlcv_ex_df["close"], name="OHLC")) fig.update_layout(title="Exemple de données OHLC sur l'actif BTC/USDT", yaxis_title="USDT", xaxis_title="Temps", xaxis_rangeslider_visible=False) fig
Le calcul général du rendement de clôture à \(p + k\) avec Pandas repose sur la méthode .shift :
rho_pk = ohlcv_df["close"].shift(-k)/ohlcv_df["close"].shift(1) - 1
Un calcul alternatif équivalent utilise la méthode .pct_change :
rho_pk = ohlcv_df["close"].pct_change(k+1).shift(-k)
Même si à notre niveau les deux méthodes précédentes sont identiques, on privilégiera dans la suite
l'utilisation de la méthode .pct_change car cette dernière possède une meilleure précision
numérique.
Calculons les rendements à \(p\) et \(p + 2\) :
#rho_p = (ohlcv_ex_df["close"].shift(0)/ohlcv_ex_df["close"].shift(1) - 1).rename("returns") #rho_p2 = (ohlcv_ex_df["close"].shift(-2)/ohlcv_ex_df["close"].shift(1) - 1).rename("returns_2") rho_p = ohlcv_ex_df["close"].pct_change(1).shift(0).rename("returns") # => équivalent à écrire rho_p = ohlcv_ex_df["close"].pct_change().rename("returns") rho_p2 = ohlcv_ex_df["close"].pct_change(3).shift(-2).rename("returns_2") rho_p_p2 = pd.concat([rho_p, rho_p2], axis=1) rho_p_p2
| returns | returns_2 | |
|---|---|---|
| time | ||
| 2021-01-01 00:00:00+00:00 | ||
| 2021-01-01 00:05:00+00:00 | -0.403% | -0.535% |
| 2021-01-01 00:10:00+00:00 | -0.368% | -0.043% |
| 2021-01-01 00:15:00+00:00 | 0.236% | 0.292% |
| 2021-01-01 00:20:00+00:00 | 0.089% | 0.207% |
| 2021-01-01 00:25:00+00:00 | -0.034% | 0.179% |
| 2021-01-01 00:30:00+00:00 | 0.152% | 0.324% |
| 2021-01-01 00:35:00+00:00 | 0.061% | 0.228% |
| 2021-01-01 00:40:00+00:00 | 0.111% | |
| 2021-01-01 00:45:00+00:00 | 0.056% |
En prenant la période \(p\) = 2021-01-01T00:05:00 et un horizon \(k = 0\), le rendement de clôture \(\rho_{p} = r_{p}\) correspond au rapport entre la clôture de la période 2021-01-01T00:05:00 et la clôture de la période 2021-01-01T00:00:00, soit : \[ \rho_{p} = \frac{\text{c}_{p}}{\text{c}_{p-1}} = \frac{28858.94}{28975.65} - 1 \simeq -0.004028 \simeq -0.403 \% \]
En prenant la période \(p\) = 2021-01-01T00:10:00 et un horizon \(k = 2\), le rendement de clôture \(\rho_{p+2}\) correspond au rapport entre la clôture de la période 2021-01-01T00:20:00 et la clôture de la période 2021-01-01T00:05:00, soit : \[ \rho_{p + 2} = \frac{\text{c}_{p+2}}{\text{c}_{p-1}} = \frac{28846.46}{28858.94} - 1 \simeq -0.000432 \simeq -0.043 \% \]
Propriété
Le rendement de clôture entre la période \(p\) et la période \(p + k\), noté \(\rho_{p + k}\), s'exprime en fonction des rendements \(r_{p}, \ldots, r_{p+k}\) (cf. Équation \eqref{org8e76f31}) comme suit :
\begin{equation} \rho_{p + k} = \prod_{i = 1}^{k} (r_{p + i} + 1) - 1 \end{equation}Ce résultat classique s'obtient en remarquant que :
\begin{align} \rho_{p + k} + 1 & = \frac{\text{c}_{p + k}}{\text{c}_{p-1}} \\ & = \frac{\text{c}_{p}}{\text{c}_{p - 1}} \frac{\text{c}_{p + 1}}{\text{c}_{p}} \ldots \frac{\text{c}_{p + k}}{\text{c}_{p + k - 1}} \\ & = (r_{p} + 1) (r_{p+1} + 1) \ldots (r_{p+k} + 1) \end{align}Déroulement pratique et livrables
Le projet est à réaliser par groupe de trois étudiant·es.
Les deux livrables suivants sont attendus.
Notebook Jupyter
Attendu :
- Rappel/Reformulation du contexte et de la problématique.
- Présentation des données (choix argumenté de la variable cible, description des indicateurs techniques que vous souhaitez étudier).
- Analyses exploratoires univariées et multivariées de votre variable cible.
- Élaboration d'un 1er modèle expliquant votre variable cible (formulation du modèle, hypothèse, variables explicatives considérées, interprétation du modèle).
- Analyse des performances du premier modèle (bien définir la notion de performance dans votre cas).
- Élaboration d'un 2nd modèle expliquant votre variable cible et analyse des performances associée.
- Une conclusion rappelant le travail réalisé, vos préconisations métiers et des perspectives pour poursuivre vos développements.
Critères d'évaluation :
| Item | Points |
|---|---|
| Fond : Identification et argumentation autour du choix de la variable cible et des variables explicatives | 2 |
| Fond : Pertinence des analyses descriptives uni et multi-variées | 2 |
| Fond : Pertinence des modélisations réalisées pour répondre à la problématique | 2 |
| Fond : Interprétation des modèles élaborés | 2 |
| Fond : Mise en oeuvre d'une démarche d'évaluation des performances | 2 |
| Forme : Structuration du notebook (titre, sections informatives) | 2 |
| Forme : Figures correctement légendées | 2 |
| Forme : Style rédactionnel professionnel ("je", "nous", "on" interdits) | 2 |
| Forme : Qualité de l'orthographe | 2 |
| Technique : Le notebook s'éxécute sans erreur | 2 |
Deadline : 22 juin 2023 00h00
Restitution orale
Attendu : Vous réaliserez une présentation technique de vos travaux permettant à l'évaluateur :
- de comprendre votre problématique par une mise en contexte de votre travail ;
- de valider la qualité scientifique des traitements et modélisation réalisés ;
- d'observer les principaux résultats.
Vous expliquerez donc précisément la/l'/les méthodologies/algorithmes mis en oeuvre (sans entrer dans le code mais en vous appuyant par exemple sur des schémas et des diagrammes pédagogiques).
Modalités :
- Date : 23/06/2023, 13h30-14h45
- Salle : À définir
- Durée : 35 min : 20 min de présentation + 15 min de questions/discussions
Critères d'évaluation :
| Item | Points |
|---|---|
| Fond : Mise en contexte | 2 |
| Fond : Choix des variables et analyses descriptives | 2 |
| Fond : Présentation rigoureuse des modélisations réalisées | 2 |
| Fond : Interprétation des modèles | 2 |
| Fond : Présentation des principaux résultats | 2 |
| Forme : Titre et sections informatives | 2 |
| Forme : Qualité des slides (légendes, lisibilité, travail des sorties logicielles, etc) | 2 |
| Forme : Clarté de la présentation orale | 2 |
| Fond : Pertinence des réponses aux questions | 2 |
| Timing : Respect de la contrainte temporelle lors de la soutenance. | 2 |
Pour se lancer en douceur
Rappel de la problématique
L'objectif du projet consiste à expliquer les rendements futurs de la cotation BTC/USDT. En effet, prévoir avec un bon niveau de précision les prochaines variations de la cotation du BTC/USDT, permettrait d'élaborer des stratégies d'investissement rentable. Dans le domaine de la finance des marchés, ce travail est réalisé par les analystes quantitatifs (également appelés quant).
Question : Imaginez que vous disposez d'un modèle permettant, à chaque période \(p\), de prévoir le rendement du BTC/USDT à \(k\) unités de temps dans le futur, i.e. \(\rho_{p+k}\). Comment pourriez-vous utiliser cette information pour investir dans ce marché ?
Construction de la variable cible
Dans notre problématique, la variable doit représenter les rendements futurs du BTC/USDT. Dans un premier temps, il est donc nécessaire de décider de l'horizon futur des rendements à prévoir. Prenons un exemple en considérant un horizon d'une heure. Sachant que les données utilisées sont échantillonnées avec une période de 5 min, il faut calculer à chaque période \(p\) le rendement à \(p + k\) où \(k = 60~\text{min} / 5~\text{min} = 12\).
On commence par charger les données.
import pandas as pd ohlcv_df = pd.read_csv("btc_5m_2021_2023.csv.bz2", compression="bz2", index_col="time")
Puis, on calcule les rendements futurs sur un horizon de 1 heure (soit \(k=12\) unités de temps).
k = 12 returns = ohlcv_df["close"].pct_change(k+1).shift(-k).rename(f"r{k}")
Analyse descriptive univariée
Nous pouvons alors faire une analyse univariée rapide de notre variable cible.
Statistiques de base :
returns.describe()
| r12 | |
|---|---|
| count | 2.1023e+05 |
| mean | 2.2043e-06 |
| std | 0.008571 |
| min | -0.22891 |
| 25% | -0.0034036 |
| 50% | 3.6285e-05 |
| 75% | 0.003419 |
| max | 0.17927 |
Premières valeurs (1 semaine = 2016*5 min)
import plotly.express as px fig_returns = px.line(returns.head(2016), title="Rendements du BTC/USDT à p+12", markers=True, labels=dict( value=returns.name)) fig_returns.update_layout(showlegend=False) fig_returns
Distribution
import plotly.express as px fig_returns_hist = px.histogram(returns, title="Distribution des rendements du BTC/USDT à p+12", labels=dict(value=returns.name)) fig_returns_hist.update_layout(showlegend=False) fig_returns_hist
Question : En tant qu'analystes quantitifs, que vous apprennent ces premières analyses sur les rendements du BTC/USDT sur un horizon futur de 1h ?
Création des variables explicatives
Dans ce projet, nous proposons d'expliquer les variations du BTC/USDT à partir d'indicateurs techniques financiers. Il existe un très grand nombre d'indicateurs techniques utilisés classiquement dans le domaine de la finance. Parmi les plus connus, on trouve :
- le RSI (Relative Strength Index) ;
- le MACD (Moving Average Convergence Divergence) ;
- les Bandes de Bollinger ;
- le Stochastique.
Tous ces indicateurs se calculent à partir des données OHLCV du BTC/USDT disponibles. De plus, la
librairie pandas_ta (pip install pandas_ta) met à disposition les fonctions de calcul des principaux indicateurs
techniques.
Calcul de l'indicateur RSI
Le RSI est un indicateur technique permettant d'évaluer la vitesse et le changement des mouvements de prix d'un actif. Le RSI oscille entre 0 et 100 et est principalement utilisé pour identifier les conditions de surachat et de survente. Si l'indicateur RSI est grand (e.g. supérieur à 70), cela suggère que l'actif est suracheté, ce qui signifie que le prix pourrait baisser à l'avenir. En revanche, si l'indicateur est faible (e.g. inférieur à 30), cela peut indiquer que l'actif est survendu et que le prix pourrait augmenter.
L'indicateur RSI possède un paramètre appelé période ou fenêtre du RSI. Ce paramètre détermine le nombre de périodes (dans notre cas une période = 5 min) à prendre en compte pour le calcul de l'indicateur. La période du RSI influence la sensibilité de l'indicateur. Une période plus courte rendra le RSI plus sensible aux variations de prix, produisant plus de signaux de surachat et de survente. En revanche, une période plus longue rendra le RSI moins sensible, produisant moins de ces signaux, et dans ce cas, ces derniers peuvent être considérés comme plus fiables.
Notes :
- comme tous les indicateurs techniques, le RSI n'est pas parfait et ne permet pas à lui seul de prédire le cours futur d'un actif. En revanche, il peut être intéressant de mesurer son pouvoir explicatif, puis de l'utiliser en conjonction avec d'autres indicateurs techniques.
- Il n'y a pas de "meilleure" période de RSI universelle ; le choix dépend de la stratégie d'investissement, de la volatilité de l'actif, et d'autres facteurs. Il est toujours recommandé de tester différentes périodes pour voir laquelle fonctionne le mieux pour la stratégie d'investissement considérée.
Calculons par exemple le RSI avec une fenêtre de deux heures (i.e. 24 périodes de 5 min).
import pandas_ta as ta # Calcul du RSI avec une fenêtre d'une journée (24 périodes de 5 minutes) rsi = ta.rsi(ohlcv_df['close'], length=24) rsi
Notes :
Pour calculer le RSI, vous devez avoir au moins autant de points de données que la taille
de la fenêtre spécifiée. Ceci explique pourquoi les 24 premières valeurs de la Series rsi sont
à NaN.
Visualisation du RSI(24) sur 1 semaine = 2016*5 min.
fig_rsi = px.line(rsi.head(2016), title=f"{rsi.name}", markers=True, labels=dict( value=rsi.name)) fig_rsi.update_layout(showlegend=False) fig_rsi.update_yaxes(range=[0, 100]) fig_rsi
À ce stade, nous pouvons créer un DataFrame qui contiendra tous les indicateurs que nous souhaitons utiliser
pour prédire les rendements du BTC/USDT :
indics_df = rsi.to_frame()
Ajoutons deux autres indicateurs RSI en changeant la fenêtre de calcul :
indics_df.ta.rsi(close=ohlcv_df["close"], length=5, append=True) indics_df.ta.rsi(close=ohlcv_df["close"], length=10, append=True) indics_df.ta.rsi(close=ohlcv_df["close"], length=30, append=True) indics_df
Analyse exploratoire multivariée
Dans ce projet, le but de l'analyse exploratoire multivariée consiste à identifier d'éventuelles liens entre les variables explicatives retenues (pour l'instant des indicateurs de type RSI) et la variable cible (rendements à 1h).
Pour ce faire, nous pouvons réaliser une analyse visuelle avec un diagramme en paires.
indics_target = pd.concat([indics_df, returns], axis=1) fig_pairs = px.scatter_matrix( indics_target, title="Diagramme en paire") fig_pairs